package info.macnana.online.jwt.helper;

import info.macnana.online.core.utils.JavaMapUtils;
import info.macnana.online.jwt.config.JwtConfig;
import info.macnana.online.user.model.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.*;

/**
 * author: zhengheng
 * github: https://github.com/macnana777
 * email: 517862340@qq.com
 * <p>
 * Date: 2017-08-03 10:31
 * Description: jwt验证工具类
 * Copyright(©) 2017 by zhengheng.
 */
@Component
public class JwtHelper {

    private static final Logger LOGGER = LoggerFactory.getLogger(JwtHelper.class);

    @Autowired
    private JwtConfig jwtConfig;

    public String createJWT(User user) {
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        //生成签名密钥
        String base64Security = jwtConfig.getBase64Secret();
        Key signingKey = deserializeKey(base64Security);
        //添加构成JWT的参数
        Map<String,Object> claims = JavaMapUtils.beanToMap(user);
        JwtBuilder jwtBuilder = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                // 用户名写入标题
                .setSubject(user.getUsername())
                //声明数据
                .setClaims(claims)
                //JWT ID
                .setId(jwtConfig.getClientId())
                //签发者
                .setIssuer(jwtConfig.getName())
                .setIssuedAt(new Date())
                .signWith(getSignatureAlgorithm(), signingKey);
        if (jwtConfig.getExpiresSecond() > 0) {
            Long expMillis = nowMillis + jwtConfig.getExpiresSecond();
            Date exp = new Date(expMillis);
            //过期时间
            jwtBuilder.setExpiration(exp).setNotBefore(now);
        }
        //生成JWT
        return jwtBuilder.compact();
    }

    private SignatureAlgorithm getSignatureAlgorithm() {
        return SignatureAlgorithm.HS256;
    }

    private Key deserializeKey(String encodedKey){
        byte[] apiKeySecretBytes = Base64.getDecoder().decode(encodedKey);
        return new SecretKeySpec(apiKeySecretBytes, getSignatureAlgorithm().getJcaName());
    }

    private String serializeKey(Key key) {
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }

    private Claims parseJWT(String jsonWebToken) throws Exception {
        String base64Security = jwtConfig.getBase64Secret();
        return Jwts.parser()
                .setSigningKey(deserializeKey(base64Security))
                .parseClaimsJws(jsonWebToken).getBody();
    }

    private User getUserFromToken(String token){
        User user = null;
        try {
            Claims claims = parseJWT(token);
            user = JavaMapUtils.mapToBean(claims,new User());
        } catch (Exception e) {
            LOGGER.error("转换token异常 , token : {}", token ,e);
        }
        return user;
    }

    private Boolean isTokenExpired(String token) {
        Boolean flag = false;
        try {
            Date expiration = getExpirationDateFromToken(token);
            flag = expiration.before(new Date());
        }catch (Exception e){
            LOGGER.error("转换token异常 , token : {}", token ,e);
        }
        return flag;
    }

    public User validateToken(String token) {
        User user = null;
        //判断是否过期
        if(!isTokenExpired(token)){
            user = getUserFromToken(token);
        }
        return user;
    }

    public Date getExpirationDateFromToken(String token) {
        Date expiration;
        try {
            final Claims claims = parseJWT(token);
            expiration = claims.getExpiration();
        } catch (Exception e) {
            expiration = null;
        }
        return expiration;
    }

}
